package com.xcity.robot;

import java.net.InetSocketAddress;
import java.util.Queue;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.apache.mina.core.future.CloseFuture;
import org.apache.mina.core.future.ConnectFuture;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.transport.socket.SocketConnector;
import org.apache.mina.transport.socket.nio.NioSocketConnector;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.xcity.WindowsShutdown;
import com.xcity.robot.net.NetIoHandler;
import com.xcity.robot.net.pomelo.PomeloDecoder;
import com.xcity.robot.net.pomelo.PomeloEncoder;
import com.xcity.robot.net.websocket.WebsocketDecoder;
import com.xcity.robot.net.websocket.WebsocketEncoder;

import naga.x.common.Config;
import naga.x.net.impl.pomelo.config.Dictionary;

/**
 * The robot main
 *
 */
public class App {
	
	static final int THREAD_COUNT = 50;
	static final ScheduledExecutorService SCHEDULE = Executors.newSingleThreadScheduledExecutor();
	
	public static void main(String[] args) {
		
		JSON.DEFAULT_GENERATE_FEATURE = SerializerFeature.config(JSON.DEFAULT_GENERATE_FEATURE, SerializerFeature.WriteEnumUsingToString, false);
		JSON.DEFAULT_GENERATE_FEATURE = SerializerFeature.config(JSON.DEFAULT_GENERATE_FEATURE, SerializerFeature.WriteEnumUsingName, false);
		
		// avoid null pointer exception in WebSocketDecoder
		naga.x.App.getApp().setConfig(new Config());
//		naga.x.App.getApp().getConfig().put(Config.WEBSOCKET_REMOTE_ADDR, "localhost");
		naga.x.App.getApp().getConfig().remoteAddr = "localhost";
//		naga.x.App.getApp().getConfig().put(Config.WEBSOCKET_PORT, 30100);
		naga.x.App.getApp().getConfig().port = 30100;
		
		int[] c = new int[1];
		final NetIoHandler handler = new NetIoHandler();
		final Queue<ConnectFuture> futures = new LinkedBlockingQueue<ConnectFuture>();
		SCHEDULE.scheduleAtFixedRate(new Runnable() {
			public void run() {
				final SocketConnector conn = new NioSocketConnector();
				conn.getFilterChain().addLast("codec.websocket", new ProtocolCodecFilter(new WebsocketEncoder(), new WebsocketDecoder()));
				conn.getFilterChain().addLast("codec.pomelo", new ProtocolCodecFilter(new PomeloEncoder(), new PomeloDecoder()));
				conn.setHandler(handler);
				ConnectFuture cf = conn.connect(new InetSocketAddress("121.41.120.228", 30100));
//				ConnectFuture cf = conn.connect(new InetSocketAddress("127.0.0.1", 3010));
//				cf.awaitUninterruptibly();
				futures.offer(cf);
				System.out.println("count:::" + ++c[0]);
			}
		}, 0, 1, TimeUnit.SECONDS);
		
		Runtime.getRuntime().addShutdownHook(new Thread() {
			@Override
			public void run() {
				System.out.println("shutdown try: " + futures.size());
				SCHEDULE.shutdownNow();
				try {
					SCHEDULE.awaitTermination(10, TimeUnit.SECONDS);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				ConnectFuture f;
				while ((f = futures.poll()) != null) {
					if (!f.isConnected() && !f.isCanceled()) {
						f.awaitUninterruptibly();
					}
					IoSession sess = f.getSession();
					if (sess != null) {
						CloseFuture close = sess.closeOnFlush();
						try {
							close.awaitUninterruptibly();
						} catch (Exception e) {
							e.printStackTrace();
						}
					} else {
						System.out.println("shutdown: session null.");
					}
				}
				System.out.println("shutdown ok: " + futures.size());
			}
		});
		
		WindowsShutdown.listen();
		
	}
	
	public static class Config extends naga.x.common.Config {
		public Dictionary dictionary;
	}
}
